package com.imut.lagain.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;


@Component
public class FileUtil {
    private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
    
    @Value("${file.upload.path}")
    private String uploadPath;
    
    @Value("${server.servlet.context-path:}")
    private String contextPath;
    
    @Value("${file.access.url}")
    private String accessUrl;
    
    // 支持的图片类型
    private static final String[] IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".gif", ".webp"};
    
    // 支持的语音类型
    private static final String[] VOICE_EXTENSIONS = {".mp3", ".wav", ".m4a", ".aac", ".amr"};
    
    // 最大文件大小 (10MB)
    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024;
    
    // 最大音频文件大小 (20MB)
    private static final long MAX_AUDIO_FILE_SIZE = 20 * 1024 * 1024;
    
    /**
     * 上传图片
     * @param file 图片文件
     * @return 文件访问URL
     * @throws IOException IO异常
     */
    public String uploadImage(MultipartFile file) throws IOException {
        log.info("开始上传图片: originalFilename={}, contentType={}, size={}", 
                file.getOriginalFilename(), file.getContentType(), file.getSize());
        
        // 检查文件是否为空
        if (file.isEmpty()) {
            log.warn("上传的文件为空");
            throw new IOException("上传的文件为空");
        }
        
        // 检查文件类型
        String contentType = file.getContentType();
        if (contentType == null || !isImageFile(contentType)) {
            log.warn("不支持的图片类型: {}", contentType);
            throw new IOException("不支持的图片类型: " + contentType);
        }
        
        // 检查文件大小
        if (file.getSize() > MAX_FILE_SIZE) {
            log.warn("图片文件过大: {} bytes, 最大允许: {} bytes", file.getSize(), MAX_FILE_SIZE);
            throw new IOException("图片文件过大");
        }
        
        // 生成文件名
        String originalFilename = file.getOriginalFilename();
        String fileExtension = getFileExtension(originalFilename);
        // 确保文件扩展名以点号开头
        if (!fileExtension.startsWith(".")) {
            fileExtension = "." + fileExtension;
        }
        String newFilename = generateUniqueFilename() + fileExtension;
        
        // 构建文件保存路径
        String datePath = getCurrentDatePath();
        Path imageDir = Paths.get(uploadPath, "images", datePath);
        log.info("图片保存目录: {}", imageDir.toAbsolutePath());
        
        // 创建目录
        if (!Files.exists(imageDir)) {
            log.info("创建目录: {}", imageDir.toAbsolutePath());
            Files.createDirectories(imageDir);
        }
        
        // 保存文件
        Path filePath = imageDir.resolve(newFilename);
        log.info("保存文件到: {}", filePath.toAbsolutePath());
        file.transferTo(filePath);
        
        // 构建访问URL，确保与WebMvcConfig中的配置一致
        String fileUrl = buildFileUrl("images", datePath, newFilename);
        log.info("图片上传成功，访问URL: {}", fileUrl);
        return fileUrl;
    }
    
    /**
     * 上传语音文件
     * @param file 语音文件
     * @return 文件访问URL
     * @throws IOException IO异常
     */
    public String uploadAudio(MultipartFile file) throws IOException {
        log.info("开始上传语音: originalFilename={}, contentType={}, size={}", 
                file.getOriginalFilename(), file.getContentType(), file.getSize());
        
        // 检查文件是否为空
        if (file.isEmpty()) {
            log.warn("上传的文件为空");
            throw new IOException("上传的文件为空");
        }
        
        // 检查文件类型
        String contentType = file.getContentType();
        if (contentType == null || !isAudioFile(contentType)) {
            log.warn("不支持的音频类型: {}", contentType);
            throw new IOException("不支持的音频类型: " + contentType);
        }
        
        // 检查文件大小
        if (file.getSize() > MAX_AUDIO_FILE_SIZE) {
            log.warn("音频文件过大: {} bytes, 最大允许: {} bytes", file.getSize(), MAX_AUDIO_FILE_SIZE);
            throw new IOException("音频文件过大");
        }
        
        // 生成文件名
        String originalFilename = file.getOriginalFilename();
        String fileExtension = getFileExtension(originalFilename);
        // 确保文件扩展名以点号开头
        if (!fileExtension.startsWith(".")) {
            fileExtension = "." + fileExtension;
        }
        String newFilename = generateUniqueFilename() + fileExtension;
        
        // 构建文件保存路径
        String datePath = getCurrentDatePath();
        Path audioDir = Paths.get(uploadPath, "audios", datePath);
        log.info("语音保存目录: {}", audioDir.toAbsolutePath());
        
        // 创建目录
        if (!Files.exists(audioDir)) {
            log.info("创建目录: {}", audioDir.toAbsolutePath());
            Files.createDirectories(audioDir);
        }
        
        // 保存文件
        Path filePath = audioDir.resolve(newFilename);
        log.info("保存文件到: {}", filePath.toAbsolutePath());
        file.transferTo(filePath);
        
        // 构建访问URL，确保与WebMvcConfig中的配置一致
        String fileUrl = buildFileUrl("audios", datePath, newFilename);
        log.info("语音上传成功，访问URL: {}", fileUrl);
        return fileUrl;
    }
    
    /**
     * 检查是否为有效的图片文件
     * @param filename 文件名
     * @return 是否为有效图片文件
     */
    private boolean isValidImageFile(String filename) {
        String extension = getFileExtension(filename).toLowerCase();
        for (String validExtension : IMAGE_EXTENSIONS) {
            if (validExtension.equals(extension)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 检查是否为有效的语音文件
     * @param filename 文件名
     * @return 是否为有效语音文件
     */
    private boolean isValidVoiceFile(String filename) {
        String extension = getFileExtension(filename).toLowerCase();
        for (String validExtension : VOICE_EXTENSIONS) {
            if (validExtension.equals(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查文件类型是否有效
     * @param filename 文件名
     * @return 是否为有效文件类型
     */
    public boolean isValidFileType(String filename) {
        return isValidImageFile(filename) || isValidVoiceFile(filename);
    }

    /**
     * 生成文件名
     * @param originalFilename 原始文件名
     * @return 新文件名
     */
    public String generateFileName(String originalFilename) {
        String fileExtension = getFileExtension(originalFilename);
        // 确保文件扩展名以点号开头
        if (!fileExtension.startsWith(".")) {
            fileExtension = "." + fileExtension;
        }
        return generateUniqueFilename() + fileExtension;
    }
    
    /**
     * 检查是否为图片文件
     * @param contentType 内容类型
     * @return 是否为图片文件
     */
    private boolean isImageFile(String contentType) {
        return contentType != null && (contentType.startsWith("image/") 
                || contentType.equals("application/octet-stream")); // 兼容某些情况
    }
    
    /**
     * 检查是否为音频文件
     * @param contentType 内容类型
     * @return 是否为音频文件
     */
    private boolean isAudioFile(String contentType) {
        return contentType != null && (contentType.startsWith("audio/") 
                || contentType.equals("application/octet-stream")); // 兼容某些情况
    }
    
    /**
     * 获取文件扩展名
     * @param filename 文件名
     * @return 扩展名
     */
    public String getFileExtension(String filename) {
        if (filename == null || filename.lastIndexOf('.') == -1) {
            return "";
        }
        return filename.substring(filename.lastIndexOf('.')).toLowerCase();
    }
    
    /**
     * 生成唯一文件名
     * @return 唯一文件名
     */
    private String generateUniqueFilename() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 构建文件访问URL
     * @param fileType 文件类型 (如 "images", "audios")
     * @param datePath 日期路径
     * @param filename 文件名
     * @return 文件访问URL
     */
    private String buildFileUrl(String fileType, String datePath, String filename) {
        return accessUrl + "files/" + fileType + "/" + datePath + "/" + filename;
    }
    
    /**
     * 获取当前日期路径 (yyyy/MM/dd)
     * @return 日期路径
     */
    private String getCurrentDatePath() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
    }
}